--- 模块功能：串口功能测试(非TASK版，串口帧有自定义的结构)
-- @author openLuat
-- @module uart.testUart
-- @license MIT
-- @copyright openLuat
-- @release 2018.03.27

module(...,package.seeall)

require"utils"
require"pm"

--[[
功能定义：
		 以100ms为周期循环发送cmd命令

		 uart按照帧结构接收外围设备的输入，收到正确的指令后，改变车检器的对应状态

		 数据解析：
				  如果数据长度大于等于13个字节才是有效数据，
				  第8个字节到倒数第3个字节为数据位，
				  第5+car_num*4个字节为地磁id，
				  第6+car_num*4个字节的7-6位为车检器状态。
]]


--串口ID,1对应uart1
--如果要修改为uart2，把UART_ID赋值为2即可
local UART_ID = 1
--串口读到的数据缓冲区
local rdbuf = ""


local cmd_pack = '0003FC000001B58B'


--有实际变化的车辆检测器个数
local car_num

--判断数据长度位	
local datalen_bit 


--车检器上是否有车,有车:1;无车或者车已离开:0
u1_device1 =0
u1_device2 =0
u1_device3 =0
u1_device4 =0
u1_device5 =0





--[[
函数名：judgment
功能  ：判断车检器的状态
参数  ：
		car_id	：地磁ID
		value	：带有车辆状态的值
返回值：无
]]
local function judgment(car_id,value)
	local car_status=value/64
	print("car_status:",car_status,"car_id:",car_id)
	if car_id==1 then
		if car_status == 0 then
			u1_device1=1
		elseif car_status == 3 then
			u1_device1=0
		end
	elseif car_id==2 then
		if car_status == 0 then
			u1_device2=1
		elseif car_status == 3 then
			u1_device2=0
		end
	elseif car_id==3 then
		if car_status == 0 then
			u1_device3=1
		elseif car_status == 3 then
			u1_device3=0
		end
	elseif car_id==4 then
		if car_status == 0 then
			u1_device4=1
		elseif car_status == 3 then
			u1_device4=0
		end
	elseif car_id==5 then
		if car_status == 0 then
			u1_device5=1
		elseif car_status == 3 then
			u1_device5=0
		end
	end
	print("u1_device1:",u1_device1,"u1_device2:",u1_device2,"u1_device3:",u1_device3,"u1_device4:",u1_device4,"u1_device5:",u1_device5)
end






--[[
函数名：parse
功能  ：按照帧结构解析处理一条完整的帧数据
参数  ：
        data：所有未处理的数据
返回值：第一个返回值是一条完整帧报文的处理结果，第二个返回值是未处理的数据
]]
local function parse(data)
    if not data then return end 
	local  u1_datalen = string.len(data)
	--print("u1_datalen:",u1_datalen)
	
	--查找数据中是否有命令，如果没有返回false
	local u1_head = string.find(data,utils.string.fromHex("0103"))
	--print("u1_head:",u1_head)
	if not u1_head then return false,data end  
	
	datalen_bit=string.byte(data,u1_head+2)
	--print("datalen_bit:",datalen_bit)
	
	--如果数据接受不完整，则返回false继续接受数据	
	if datalen_bit==4 then
		car_num=0
		if string.len(data) < datalen_bit+u1_head+4  then return false,data end
	elseif datalen_bit==8 then
		car_num=1
		if string.len(data) < datalen_bit+u1_head+4 then return false,data end
	elseif datalen_bit==12 then
		car_num=2
	    if string.len(data) < datalen_bit+u1_head+4 then return false,data end
	elseif datalen_bit==16 then
		car_num=3
		if string.len(data) < datalen_bit+u1_head+4 then return false,data end
	elseif datalen_bit==20 then	
		car_num=4
		if string.len(data) < datalen_bit+u1_head+4 then return false,data end
	elseif datalen_bit==24 then
		car_num=5
		if string.len(data) < datalen_bit+u1_head+4 then return false,data end
	else
		return false,data
	end
	
	if car_num ~=nil and car_num~=0 then
		if car_num == 1 then
			judgment(string.byte(data,u1_head+8),string.byte(data,u1_head+9))
		elseif car_num == 2 then
			judgment(string.byte(data,u1_head+8),string.byte(data,u1_head+9))
			judgment(string.byte(data,u1_head+12),string.byte(data,u1_head+13))
		elseif car_num == 3 then
			judgment(string.byte(data,u1_head+8),string.byte(data,u1_head+9))
			judgment(string.byte(data,u1_head+12),string.byte(data,u1_head+13))
			judgment(string.byte(data,u1_head+16),string.byte(data,u1_head+17))
		elseif car_num == 4 then
			judgment(string.byte(data,u1_head+8),string.byte(data,u1_head+9))
			judgment(string.byte(data,u1_head+12),string.byte(data,u1_head+13))
			judgment(string.byte(data,u1_head+16),string.byte(data,u1_head+17))
			judgment(string.byte(data,u1_head+20),string.byte(data,u1_head+21))
		elseif car_num == 5 then
			judgment(string.byte(data,u1_head+8),string.byte(data,u1_head+9))
			judgment(string.byte(data,u1_head+12),string.byte(data,u1_head+13))
			judgment(string.byte(data,u1_head+16),string.byte(data,u1_head+17))
			judgment(string.byte(data,u1_head+20),string.byte(data,u1_head+21))
			judgment(string.byte(data,u1_head+24),string.byte(data,u1_head+25))
		end	
	end
	return true,string.sub(data,datalen_bit+u1_head+4,-1)
	
	
end

--[[
函数名：proc
功能  ：处理从串口读到的数据
参数  ：
        data：当前一次从串口读到的数据
返回值：无
]]
local function proc(data)
    if not data or string.len(data) == 0 then return end
    --追加到缓冲区
    rdbuf = rdbuf..data    
    
    local result,unproc
    unproc = rdbuf
    --根据帧结构循环解析未处理过的数据
    while true do
        result,unproc = parse(unproc)
        if not unproc or unproc == "" or not result then
            break
        end
    end

    rdbuf = unproc or ""
end

--[[
函数名：read
功能  ：读取串口接收到的数据
参数  ：无
返回值：无
]]
local function read()
    local data = ""
    --底层core中，串口收到数据时：
    --如果接收缓冲区为空，则会以中断方式通知Lua脚本收到了新数据；
    --如果接收缓冲器不为空，则不会通知Lua脚本
    --所以Lua脚本中收到中断读串口数据时，每次都要把接收缓冲区中的数据全部读出，这样才能保证底层core中的新数据中断上来，此read函数中的while语句中就保证了这一点
    while true do        
        data = uart.read(UART_ID,"*l")
        if not data or string.len(data) == 0 then break end
        proc(data)
    end
end

--[[
函数名：write
功能  ：通过串口发送数据
参数  ：
        s：要发送的数据
返回值：无
]]
function write(s)
    --log.info("testUart.write",s)
    uart.write(UART_ID,s)
end


sys.timerLoopStart(write,100,utils.string.fromHex(cmd_pack))


local function writeOk()
    log.info("testUart.writeOk")
end







--保持系统处于唤醒状态，此处只是为了测试需要，所以此模块没有地方调用pm.sleep("testUart")休眠，不会进入低功耗休眠状态
--在开发“要求功耗低”的项目时，一定要想办法保证pm.wake("testUart")后，在不需要串口时调用pm.sleep("testUart")
pm.wake("uart1")
--注册串口的数据接收函数，串口收到数据后，会以中断方式，调用read接口读取数据
uart.on(UART_ID,"receive",read)
--注册串口的数据发送通知函数
uart.on(UART_ID,"sent",writeOk)

--配置并且打开串口
uart.setup(UART_ID,9600,8,uart.PAR_NONE,uart.STOP_1)
--如果需要打开“串口发送数据完成后，通过异步消息通知”的功能，则使用下面的这行setup，注释掉上面的一行setup
--uart.setup(UART_ID,115200,8,uart.PAR_NONE,uart.STOP_1,nil,1)
